package cn.kinoko.aspect;

import cn.kinoko.common.aspect.annotation.OwnershipCheck;
import cn.kinoko.common.code.ErrorCodeEnum;
import cn.kinoko.common.utils.ExceptionUtil;
import cn.kinoko.model.cnTeam.vo.MemberVO;
import cn.kinoko.model.manga.entity.Manga;
import cn.kinoko.service.common.CommonService;
import cn.kinoko.service.common.util.AuthUtil;
import cn.kinoko.service.manga.MangaService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author kinoko
 */
@Slf4j
@Aspect
@Component
public class OwnershipCheckAspect {

    // 创建参数名称解析器
    private static final DefaultParameterNameDiscoverer PARAMETER_NAME_DISCOVERER = new DefaultParameterNameDiscoverer();
    // 创建spel表达式解析器
    private static final SpelExpressionParser PARSER = new SpelExpressionParser();

    @Resource
    private CommonService commonService;
    @Resource
    private MangaService mangaService;

    @Around("@annotation(ownershipCheck)")
    public Object around(ProceedingJoinPoint joinPoint, OwnershipCheck ownershipCheck) throws Throwable {
        // 获取操作用户id
        Long uid = AuthUtil.getUidAndCheck();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // 获取切面方法
        Method method = signature.getMethod();
        // 获取参数名称
        String[] parameterNames = PARAMETER_NAME_DISCOVERER.getParameterNames(method);
        // 获取参数
        Object[] parameterValues = joinPoint.getArgs();
        // 解析业务id
        Optional<List<Long>> bizIds = parseBizId(ownershipCheck.bizId(), parameterNames, parameterValues);
        // 执行校验
        bizIds.ifPresent(ids -> {
            // 判断是业务实体是否为漫画，且为共享行为
            if (ownershipCheck.bizClass().equals(Manga.class) && ownershipCheck.isShared()) {
                ids.forEach(id -> {
                    // 查询漫画的人员ID
                    List<Long> members = mangaService.mangaMember(id).stream().map(MemberVO::getUid).toList();
                    // 查看当前漫画坑组参与人中是否有当前登录用户
                    ExceptionUtil.assertion(!members.contains(uid), ErrorCodeEnum.USER_ERROR_A0300);
                });
            } else {
                // 查询操作的业务对象
                List<Map<String, Object>> entityList = commonService.queryObj(ownershipCheck.bizClass(), ids);
                entityList.forEach(entity -> {
                    // 检查业务对象的创建人是否为当前登录用户
                    if (!uid.equals(Long.parseLong(entity.get("create_by").toString())))
                        ExceptionUtil.throwOut(ErrorCodeEnum.USER_ERROR_A0300);
                });
            }
        });
        // 执行业务方法
        return joinPoint.proceed();
    }

    /**
     * 解析业务id
     *
     * @param spel            spel表达式
     * @param parameterNames  参数名称
     * @param parameterValues 参数值
     * @return 解析结果
     */
    private static Optional<List<Long>> parseBizId(String spel, String[] parameterNames, Object[] parameterValues) {
        if (StringUtils.isNotBlank(spel) && parameterNames != null && parameterNames.length != 0) {
            // 创建评估上下文
            EvaluationContext evaluationContext = new StandardEvaluationContext();
            // 为表达式设置参数变量
            for (int i = 0; i < parameterValues.length; ++i) {
                evaluationContext.setVariable(parameterNames[i], parameterValues[i]);
            }
            Expression expression = PARSER.parseExpression(spel);
            Object value = expression.getValue(evaluationContext);
            // 匹配业务id类型
            return matchBizIdType(value);
        }
        return Optional.empty();
    }

    /**
     * 匹配业务id类型
     *
     * @param value 业务id
     * @return 解析结果
     */
    private static Optional<List<Long>> matchBizIdType(Object value) {
        // 如果是Long类型，直接返回
        if (value instanceof Long) {
            return Optional.of(Collections.singletonList((Long) value));
        }
        // 如果是Integer类型，转Long返回
        if (value instanceof Integer) {
            return Optional.of(Collections.singletonList(Long.valueOf((Integer) value)));
        }
        // 如果是List类型，转Long返回
        if (value instanceof List) {
            if (((List<?>) value).get(0) instanceof Long) {
                return Optional.of((List<Long>) value);
            } else if (((List<?>) value).get(0) instanceof Integer) {
                return Optional.of(((List<Integer>) value).stream().map(Long::valueOf).collect(Collectors.toList()));
            }
        }
        // 如果是long[]类型，转为List<Long>
        if (value instanceof Long[]) {
            return Optional.of(Arrays.asList((Long[]) value));
        }
        // 如果是int[]类型，转为List<Long>
        if (value instanceof Integer[]) {
            return Optional.of(Arrays.stream((Integer[]) value).mapToLong(Long::valueOf).boxed().collect(Collectors.toList()));
        }
        return Optional.empty();
    }


}
